# -*- coding: utf-8 -*-
# Author   : ZhangQing
# Time     : 2025-08-04 23:42
# File     : connection.py
# Project  : codebuddy_craft
# Desc     : 数据库连接
# backend/database/connection.py
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine, async_sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import MetaData, text
from sqlalchemy.pool import NullPool
from typing import AsyncGenerator
import logging

from backend.utils.config import settings
from backend.utils.logger import logger

# 创建基础模型类
Base = declarative_base()

# 数据库引擎
engine = None
async_session_maker = None

# 元数据约定，用于命名约束
naming_convention = {
    "ix": "ix_%(column_0_label)s",
    "uq": "uq_%(table_name)s_%(column_0_name)s",
    "ck": "ck_%(table_name)s_%(constraint_name)s",
    "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
    "pk": "pk_%(table_name)s"
}

Base.metadata = MetaData(naming_convention=naming_convention)


def get_database_url() -> str:
    """获取数据库连接URL"""
    
    if settings.DATABASE_URL:
        # 如果配置了完整的数据库URL，直接使用
        return settings.DATABASE_URL
    else:
        # 根据配置项构建数据库URL
        if settings.DB_TYPE.lower() == "postgresql":
            return f"postgresql+asyncpg://{settings.DB_USER}:{settings.DB_PASSWORD}@{settings.DB_HOST}:{settings.DB_PORT}/{settings.DB_NAME}"
        elif settings.DB_TYPE.lower() == "mysql":
            return f"mysql+aiomysql://{settings.DB_USER}:{settings.DB_PASSWORD}@{settings.DB_HOST}:{settings.DB_PORT}/{settings.DB_NAME}"
        elif settings.DB_TYPE.lower() == "sqlite":
            return f"sqlite+aiosqlite:///{settings.DB_NAME}"
        else:
            raise ValueError(f"不支持的数据库类型: {settings.DB_TYPE}")


async def create_database_engine():
    """创建数据库引擎"""
    global engine, async_session_maker
    
    try:
        # 获取数据库URL
        database_url = get_database_url()
        logger.info(f"正在连接数据库: {database_url.split('@')[0]}@****")
        
        # 创建异步引擎
        engine_kwargs = {
            "echo": settings.DEBUG,  # 在调试模式下显示SQL语句
            "future": True,
            "pool_pre_ping": True,  # 连接前ping，确保连接有效
        }
        
        # SQLite特殊配置
        if "sqlite" in database_url:
            engine_kwargs.update({
                "poolclass": NullPool,  # SQLite不需要连接池
                "connect_args": {"check_same_thread": False}
            })
        else:
            engine_kwargs.update({
                "pool_size": getattr(settings, 'DB_POOL_SIZE', 5),
                "max_overflow": getattr(settings, 'DB_MAX_OVERFLOW', 10),
                "pool_timeout": getattr(settings, 'DB_POOL_TIMEOUT', 30),
                "pool_recycle": getattr(settings, 'DB_POOL_RECYCLE', 3600),
            })
        
        engine = create_async_engine(database_url, **engine_kwargs)
        
        # 创建会话工厂
        async_session_maker = async_sessionmaker(
            engine, 
            class_=AsyncSession, 
            expire_on_commit=False
        )
        
        logger.info("✅ 数据库引擎创建成功")
        
    except Exception as e:
        logger.error(f"❌ 数据库引擎创建失败: {str(e)}")
        raise


async def test_database_connection():
    """测试数据库连接"""
    try:
        async with engine.begin() as conn:
            await conn.execute(text("SELECT 1"))
        logger.info("✅ 数据库连接测试成功")
        return True
    except Exception as e:
        logger.error(f"❌ 数据库连接测试失败: {str(e)}")
        return False


async def get_async_session() -> AsyncGenerator[AsyncSession, None]:
    """获取异步数据库会话"""
    async with async_session_maker() as session:
        try:
            yield session
        except Exception:
            await session.rollback()
            raise
        finally:
            await session.close()


async def get_db() -> AsyncGenerator[AsyncSession, None]:
    """FastAPI依赖项：获取数据库会话"""
    async for session in get_async_session():
        yield session


async def close_database():
    """关闭数据库连接"""
    global engine
    if engine:
        await engine.dispose()
        logger.info("✅ 数据库连接已关闭")


async def health_check() -> dict:
    """数据库健康检查"""
    try:
        async with engine.begin() as conn:
            result = await conn.execute(text("SELECT 1 as health"))
            health_result = result.scalar()
            
            if health_result == 1:
                return {
                    "status": "healthy",
                    "database": "connected",
                    "engine": str(engine.url).split('@')[0] + "@****"
                }
            else:
                return {
                    "status": "unhealthy",
                    "database": "disconnected",
                    "error": "查询返回异常结果"
                }
    except Exception as e:
        return {
            "status": "unhealthy",
            "database": "error",
            "error": str(e)
        }
